/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frsutl.c                                           */
/*  NOTE      =                                                    */
/*  DATE      = 2014/11/10 by yaohl                                */
/*******************************************************************/
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <uuid/uuid.h>
#include <unistd.h>
#include <limits.h>
#include <ctype.h>

#include "frcomm.h"
#include "frmem.h"
#include "frlog.h"

#if defined(FRLINUX4) || defined(FRLINUX5)
static char *__random_uuid( char buf[37] )
{
    const char *c = "89ab";
    char *p = buf;
    int n;
    for( n = 0; n < 16; ++n )
    {
        int b = rand()%255;
        switch( n )
        {
            case 6:
                sprintf(p, "4%x", b%15 );
            break;
            case 8:
                sprintf(p, "%c%x", c[rand()%strlen(c)], b%15 );
            break;
            default:
                sprintf(p, "%02x", b);
            break;
        }
 
        p += 2;
        switch( n )
        {
            case 3:
            case 5:
            case 7:
            case 9:
                *p++ = '-';
                break;
        }
    }
    *p = 0;
    return buf;
}
#endif

int fruuid(char *p_uuid)
{
    uuid_t uuid;

    if(p_uuid == NULL)
    	return FR_FAIL;

#if defined(FRLINUX4) || defined(FRLINUX5)
    __random_uuid(p_uuid);
#else
    uuid_generate_time(uuid);
    uuid_unparse(uuid, p_uuid);
#endif

    return FR_SUCC;
}


u_int iptools_parse_ipaddr(const char *dotted)
{
    struct in_addr addr;
    unsigned char *addrp;
    unsigned int onebyte;
    char buf[20], *p, *q;
    int i;

    if (dotted == NULL)
        return 0;

    /* copy dotted string, because we need to modify it */
    strncpy(buf, dotted, sizeof(buf) - 1);
    buf[sizeof(buf) - 1] = '\0';
    addrp = (unsigned char *)&addr.s_addr;

    p = buf;
    for (i = 0; i < 3; ++i) {
        if ((q = strchr(p, '.')) == NULL) {
            /* autocomplete, this is a network address */
            onebyte = atoi(p);
            addrp[i] = onebyte;
            while (i < 3)
                addrp[++i] = 0;

            return addr.s_addr;
        }

        *q = '\0';
        onebyte = atoi(p);
        addrp[i] = onebyte;
        p = q + 1;
    }

    /* we have checked 3 bytes, now we check the last one */
    onebyte = atoi(p);
    addrp[3] = onebyte;
    return addr.s_addr;
}


void iptools_parse_iprange(const char* dotted, u_int* min_ip, u_int* max_ip)
{
    const char *token, *cur = dotted;
    char arr_min_ip[20];
    *min_ip = 0;
    *max_ip = 0;
    
    if(dotted == NULL || dotted[0]=='\0') return;

    token = strchr(cur, '-');
    if (token==NULL)
    {
        *min_ip = iptools_parse_ipaddr(cur);
        *max_ip = *min_ip;
        return;
    }
    
    snprintf(arr_min_ip, token - cur + 1, "%s", cur);
    *min_ip = iptools_parse_ipaddr(arr_min_ip);
    *max_ip = iptools_parse_ipaddr(token + 1);
}


void iptools_parse_portrange(const char* dotted, u_short* sport, u_short* dport)
{
    const char *token,  *cur = dotted;
    *sport = 0;
    *dport = 0;

    if(dotted == NULL || dotted[0]=='\0') return;

    token = strchr(cur, '-');
    if (token==NULL)
    {
        *sport = atoi(cur);
        *dport = *sport;
        return;
    }
    
    *sport = atoi(cur);
    *dport = atoi(token + 1);
    if (*sport > *dport)
    {
        u_short port_tmp = *sport;
        *sport = *dport;
        *dport = port_tmp;
    }
}


int iptools_parse_mac(char* str_mac, unsigned char* mac, int size)
{
    unsigned int i;
    char *end;
    
    if(size!=APM_MAC_SIZE || str_mac == NULL || mac == NULL)
        return 0;

    for (i = 0; i < APM_MAC_SIZE-1; ++i) {
        mac[i] = strtoul(str_mac, &end, 16);
        if (*end != ':' || end - str_mac > 2)
           return 0;
        str_mac = end + 1;
    }

    mac[APM_MAC_SIZE-1] = strtoul(str_mac, &end, 16);
    if (*end != '\0' || end - str_mac > 2)
        return 0;
    return 1;
}


int frget_absdir(char *p_relative_path, char *p_abs_dir, unsigned int ui_size)
{
    char *p_abs_path = NULL;
    char *p_tmp = NULL;
    unsigned int ui_dir_len = 0;
    char arr_path[PATH_MAX];
    memset(arr_path, 0x0, sizeof(arr_path));

    p_abs_path = realpath(p_relative_path, arr_path);
    if (p_abs_path == NULL)
    {
        return FR_FAIL;
    }

    /* 查询最后一个/后的字符串 */
    p_tmp = strrchr(p_abs_path, '/');
    /* 取得/之前字符 */
    ui_dir_len = p_tmp - p_abs_path;
    if (ui_dir_len >= ui_size)
    {
        return FR_FAIL;
    }
    strncpy(p_abs_dir, arr_path, ui_dir_len + 1);
    p_abs_dir[ui_dir_len] = '\0';

    return FR_SUCC;
}


int frtime2str(struct timeval *p_tv , char *p_time, unsigned int ui_time_size)
{
    struct tm *p_tm = NULL;

    if(p_tv == NULL || p_time == NULL || ui_time_size <= 1)
        return FR_FAIL;

    p_tm = localtime(&(p_tv->tv_sec));

    snprintf(p_time,ui_time_size,"%04d/%02d/%02d %02d:%02d:%02d.%06d",
            p_tm->tm_year + 1900,p_tm->tm_mon + 1,p_tm->tm_mday,
            p_tm->tm_hour,p_tm->tm_min,p_tm->tm_sec,(int)p_tv->tv_usec);

    return FR_SUCC;
}


long frtime_diff(struct timeval *p_tv_pre, struct timeval *p_tv_now)
{
    return (p_tv_now->tv_sec - p_tv_pre->tv_sec)*1000000+ p_tv_now->tv_usec - p_tv_pre->tv_usec;
}



void frprint_bin(const char *p_fun, const char *p_file, unsigned int ui_line
               , const char *p_title, const char *p_data, unsigned int ui_size)
{
    char *p_buff=NULL;

    if(p_data == NULL || ui_size <= 0)
    {
        printf("%s no data", p_title);
        return;
    }

    p_buff = (char *)frmemdup(p_data, ui_size+1);
    if(p_buff == NULL)
    {
        printf("%s frmemdup err", p_title);
        return;
    }

    p_buff[ui_size] = '\0';
    printf("[%s(%s:%u)]%s[%s]", p_fun, p_file, ui_line, p_title, p_buff);
    frfree(p_buff);

    return;
}


void frl4_info(u_short ip_proto, u_int src_ip, u_short src_port, u_int dst_ip,u_short dst_port
              , unsigned int ui_data_len
              , int i_analyz_cmd
              , char *p_outbuff, unsigned int ui_buff_size)
{
    char arr_buff[128];

    if(p_outbuff == NULL || ui_buff_size <= 0)
        return;

    sprintf(arr_buff, "%s ", FR_L4PROTO2STR(ip_proto));
    strcat(arr_buff, int_ntoa (src_ip));
    sprintf(arr_buff + strlen (arr_buff), ":%i->", src_port);
    strcat(arr_buff, int_ntoa (dst_ip));
    sprintf(arr_buff + strlen (arr_buff), ":%i", dst_port);

    snprintf(p_outbuff, ui_buff_size, "%s data_len=%d analyz_cmd=%d", arr_buff, ui_data_len, i_analyz_cmd);
    return;
}


void frl4_print(const char *p_fun, const char *p_file, unsigned int ui_line
              , u_short ip_proto, u_int src_ip, u_short src_port, u_int dst_ip,u_short dst_port
              , unsigned int ui_data_len
              , int analyz_cmd)
{
    char arr_buff[128];

    sprintf(arr_buff, "%s ", FR_L4PROTO2STR(ip_proto));
    strcat(arr_buff, int_ntoa (src_ip));
    sprintf(arr_buff + strlen (arr_buff), ":%i->", src_port);
    strcat(arr_buff, int_ntoa (dst_ip));
    sprintf(arr_buff + strlen (arr_buff), ":%i", dst_port);

    printf("[%s(%s:%u)]%s data_len=%d analyz_cmd=%d\n", p_fun, p_file, ui_line, arr_buff, ui_data_len, analyz_cmd);
    return;
}


void frl4_print2(char *p_buff, unsigned int ui_buff_size
                ,u_short ip_proto, u_int src_ip, u_short src_port, u_int dst_ip,u_short dst_port)
{
    char arr_buff[128];

    if(p_buff == NULL || ui_buff_size < 2)
        return;

    sprintf(arr_buff, "%s ", FR_L4PROTO2STR(ip_proto));
    strcat(arr_buff, int_ntoa (src_ip));
    sprintf(arr_buff + strlen (arr_buff), ":%i->", src_port);
    strcat(arr_buff, int_ntoa (dst_ip));
    sprintf(arr_buff + strlen (arr_buff), ":%i", dst_port);

    snprintf(p_buff, ui_buff_size, "%s", arr_buff);
    return;
}


void frtrim(char *p_instr)
{
    int i_loop = 0;
    int i_delspace_len = 0;
    char *p_tmp = NULL;

    if (p_instr == NULL || *p_instr == '\0')
    {
        return;
    }

    p_tmp = p_instr;
    i_delspace_len = strlen(p_tmp);

    /* remove the left space '\t' */
    for (i_loop = 0; i_loop < i_delspace_len; i_loop++)
    {
        if ((p_tmp[i_loop] != ' ') && (p_tmp[i_loop] != '\t'))
        {
            break;
        }
    }

    if (i_loop > 0)
    {
        memmove(p_tmp, p_tmp + i_loop, i_delspace_len - i_loop + 1 );
    }

    /* remove the right space '\t' */
    i_loop = strlen(p_tmp) - 1;
    while (i_loop >= 0)
    {
        if ((p_tmp[i_loop] != ' ') && (p_tmp[i_loop] != '\t'))
        {
            p_tmp[i_loop + 1] = '\0';
            break;
        }
        i_loop--;
    }

    return;
}



void frltrim(char *p_instr)
{
    int i_loop = 0;
    int i_delspace_len = 0;
    char *p_tmp = NULL;

    if (p_instr == NULL || *p_instr == '\0')
    {
        return;
    }

    p_tmp = p_instr;
    i_delspace_len = strlen(p_tmp);

    /* remove the left space '\t' */
    for (i_loop = 0; i_loop < i_delspace_len; i_loop++)
    {
        if ((p_tmp[i_loop] != ' ') && (p_tmp[i_loop] != '\t'))
        {
            break;
        }
    }

    if (i_loop > 0)
    {
        memmove(p_tmp, p_tmp + i_loop, i_delspace_len - i_loop + 1 );
    }

    return;
}


void frrtrim(char *p_instr)
{
    int i_loop = 0;
    int i_delspace_len = 0;
    char *p_tmp = NULL;

    if (p_instr == NULL || *p_instr == '\0')
    {
        return;
    }

    p_tmp = p_instr;
    i_delspace_len = strlen(p_tmp);

    /* remove the right space '\t' */
    i_loop = strlen(p_tmp) - 1;
    while (i_loop >= 0)
    {
        if ((p_tmp[i_loop] != ' ') && (p_tmp[i_loop] != '\t'))
        {
            p_tmp[i_loop + 1] = '\0';
            break;
        }
        i_loop--;
    }
    //若全为空格或/t
    if(i_loop<0)
        p_tmp[0] = '\0';

    return;
}

void frrtrimLF(char *p_instr)
{
    int i_len=0;
    if(p_instr == NULL || *p_instr == '\0')
        return;

    i_len = strlen(p_instr);
    if(i_len < 1)
        return;
    if(p_instr[i_len-1] == '\n')
    {
        p_instr[i_len-1]='\0';
        if(i_len >= 2 && p_instr[i_len-2]=='\r')
            p_instr[i_len-2]='\0';
    }
    return;
}

char* frmemstr(const char* p_data, int i_data_len, char* p_substr, int i_sublen)
{
    int i;
    const char* p_cur = p_data;
    int i_check_len = 0;

    if (p_data == NULL || i_data_len <= 0
        || p_substr == NULL || i_sublen <= 0
        || i_sublen > i_data_len )
        return NULL;

    i_check_len = i_data_len - i_sublen + 1;
    for (i = 0; i < i_check_len; i++)
    {
        if (*p_cur == *p_substr)
        {
            //assert(i_data_len - i >= i_sublen);
            if (memcmp(p_cur, p_substr, i_sublen) == 0) {
                //found
                return (char*)p_cur;
            }
        }
        p_cur++;
    }

    return NULL;
}

int frstrlower(char *p_data, int i_data_len)
{
    int i_index = 0;

    if(p_data == NULL || i_data_len <= 0)
        return FR_FAIL;

    for(i_index = 0; i_index < i_data_len; i_index++)
    {
        p_data[i_index] = tolower(p_data[i_index]);
    }

    return FR_SUCC;

}

int frstrupper(char *p_data, int i_data_len)
{
    int i_index = 0;

    if(p_data == NULL || i_data_len <= 0)
        return FR_FAIL;

    for(i_index = 0; i_index < i_data_len; i_index++)
    {
        p_data[i_index] = toupper(p_data[i_index]);
    }

    return FR_SUCC;

}

uint64_t frhton64(uint64_t u64_val)
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
        uint32_t low = (uint32_t) (u64_val & 0x00000000FFFFFFFFLL);
        uint32_t high = (uint32_t) ((u64_val & 0xFFFFFFFF00000000LL) >> 32);
        low = htonl(low);
        high = htonl(high);
        return (uint64_t) high + (((uint64_t) low) << 32);;
#else
        return u64_val;
#endif
}

uint64_t frntoh64(uint64_t u64_val)
{
    uint64_t res64 = 0;
#if __BYTE_ORDER == __LITTLE_ENDIAN
    uint32_t low = (uint32_t) (u64_val & 0x00000000FFFFFFFFLL);
    uint32_t high = (uint32_t) ((u64_val & 0xFFFFFFFF00000000LL) >> 32);
    low = ntohl(low);
    high = ntohl(high);
    res64 = (uint64_t) high + (((uint64_t) low) << 32);
#else
    res64 = u64_val;
#endif
    return res64;
}

#define BUFFER_SIZE 1024

int frcopy_file(const char *p_src_file, const char *p_dst_file)
{
	FILE *p_fp_src, *p_fp_dst;
	char arr_buffer[BUFFER_SIZE];
	int i_src_len = 0, i_dst_len = 0;

	if ((p_fp_src = fopen(p_src_file, "r")) == NULL)
	{
	    FRLOG_ERROR("File [%s] open failed\n", p_src_file);
		return FR_FAIL;
	}
	if ((p_fp_dst = fopen(p_dst_file, "w")) == NULL)
	{
	    FRLOG_ERROR("File [%s] open failed\n", p_dst_file);
		fclose(p_fp_src);
		return FR_FAIL;
	}

	memset(arr_buffer, 0, BUFFER_SIZE);
	while ((i_src_len = fread(arr_buffer, 1, BUFFER_SIZE, p_fp_src)) > 0)
	{
		if ((i_dst_len = fwrite(arr_buffer, 1, i_src_len, p_fp_dst)) != i_src_len)
		{
		    FRLOG_ERROR("File [%s] write failed\n", p_dst_file);
			fclose(p_fp_src);
			fclose(p_fp_dst);
			return FR_FAIL;
		}
		memset(arr_buffer, 0, BUFFER_SIZE);
	}

	fclose(p_fp_src);
	fclose(p_fp_dst);
	return FR_SUCC;
}

int fris_print_ascii(char *p_data, int i_len)
{
    int i_idx = 0;

    if(p_data == NULL || i_len == 0)
        return 1;

    for(i_idx=0; i_idx<i_len; i_idx++)
    {
        if( *(p_data+i_idx)<32 || *(p_data+i_idx)>126)
        {
            if( *(p_data+i_idx) =='\r')
            {
                if( i_idx + 1 >= i_len)
                    return 0;
                if(*(p_data+i_idx+1) !='\n')
                    return 0;
                else
                    continue;
            }
            else if(*(p_data+i_idx) =='\t')
                continue;
            else if(*(p_data+i_idx) =='\n')
                continue;
            else
                return 0;
        }
    }
    return 1;
}
